/* 
 * Copyright 2013 Sébastien Mouquet.
 * 
 * This file is part of ECovoiturage.
 * 
 * ECovoiturage is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * ECovoiturage is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Foobar. If not, see http://www.gnu.org/licenses/.
 */
package com.smouquet.ecovoiturage.ui;

import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Component;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import java.util.ArrayList;
import java.util.List;
import org.vaadin.addon.borderlayout.BorderLayout;

/**
 * Fenêtre d'assistant. Cette fenêtre permet de gérer plusieurs étapes.
 * Elle s'occupe de la gestion du passage des étapes, des boutons correspondant...
 * 
 * @author sebastien.mouquet
 */
public class Wizard extends Window implements Button.ClickListener
{
    private VerticalLayout container;
    private Button btnPrevious;
    private Button btnNext;
    private Button btnFinish;
    private Button btnCancel;
    
    private List<Step> steps;
    private int currentStepIndex;
    
    
    public Wizard()
    {
        this.steps = new ArrayList<Step>();
        this.currentStepIndex = -1;
        layout();
    }
    
    public Wizard(String caption)
    {
        super(caption);
        this.steps = new ArrayList<Step>();
        this.currentStepIndex = -1;
        layout();
    }
    
    
    public void addStep(Step step)
    {
        steps.add(step);
    }

    public List<Step> getSteps()
    {
        return steps;
    }

    public int getCurrentStepIndex() {
        return currentStepIndex;
    }
    
    public void start()
    {
        if(currentStepIndex != -1) {
            throw new IllegalStateException("start cannot be call during wizard");
        }
        if(steps.isEmpty()) {
            throw new IllegalStateException("start cannot be call witout step");
        }
        
        currentStepIndex++;
        refreshButtonsState();
        
        Step step = steps.get(currentStepIndex);
        step.attachWizard(this);
        container.addComponent(step.init());
        step.run();
    }
    
    public void setPreviousEnabled(boolean enable)
    {
        btnPrevious.setEnabled(enable);
    }
    
    public void setNextEnabled(boolean enable)
    {
        btnNext.setEnabled(enable);
    }
    
    public void setFinishEnabled(boolean enable)
    {
        btnFinish.setEnabled(enable);
    }
    
    public void setCancelEnabled(boolean enable)
    {
        btnCancel.setEnabled(enable);
    }
    
    
    private void layout()
    {
        container = new VerticalLayout();
        container.setSizeFull();
        btnPrevious = new Button("Précédent", this);
        btnNext = new Button("Suivant", this);
        btnFinish = new Button("Terminer", this);
        btnCancel = new Button("Annuler", this);
        
        HorizontalLayout btnLayout = new HorizontalLayout();
        btnLayout.setSpacing(true);
        btnLayout.addComponent(btnPrevious);
        btnLayout.addComponent(btnNext);
        btnLayout.addComponent(btnFinish);
        btnLayout.addComponent(btnCancel);
        btnLayout.setComponentAlignment(btnPrevious, Alignment.MIDDLE_RIGHT);
        btnLayout.setComponentAlignment(btnNext, Alignment.MIDDLE_RIGHT);
        btnLayout.setComponentAlignment(btnFinish, Alignment.MIDDLE_RIGHT);
        btnLayout.setComponentAlignment(btnCancel, Alignment.MIDDLE_RIGHT);
        
        GridLayout buttonLayout = new GridLayout(1, 1);
        buttonLayout.setWidth("100%");
        buttonLayout.setHeight(50, Unit.PIXELS);
        buttonLayout.setMargin(true);
        buttonLayout.addComponent(btnLayout);
        buttonLayout.setComponentAlignment(btnLayout, Alignment.MIDDLE_RIGHT);
        
        BorderLayout layout = new BorderLayout();
        layout.setSizeFull();
        layout.addComponent(container, BorderLayout.Constraint.CENTER);
        layout.addComponent(buttonLayout, BorderLayout.Constraint.SOUTH);
        
        setContent(layout);
    }
    
    private void refreshButtonsState()
    {
        boolean currentIsFirst = currentStepIndex == 0;
        boolean currentIsLast = currentStepIndex == (steps.size() - 1);
        
        btnPrevious.setEnabled(!currentIsFirst);
        btnNext.setEnabled(!currentIsLast);
        btnFinish.setEnabled(currentIsLast);
    }

    
    @Override
    public void buttonClick(ClickEvent event)
    {
        if(btnPrevious.equals(event.getButton()))
        {
            if(steps.get(currentStepIndex).onBeforePrevious())
            {
                currentStepIndex--;
                refreshButtonsState();
                
                Step step = steps.get(currentStepIndex);
                step.attachWizard(this);
                container.removeAllComponents();
                container.addComponent(step.init());
                step.onAfterPrevious();
            }
        }
        else if(btnNext.equals(event.getButton()))
        {
            if(steps.get(currentStepIndex).onBeforeNext())
            {
                currentStepIndex++;
                refreshButtonsState();
                
                Step step = steps.get(currentStepIndex);
                step.attachWizard(this);
                container.removeAllComponents();
                container.addComponent(step.init());
                step.run();
                step.onAfterNext();
            }
        }
        else if(btnFinish.equals(event.getButton()))
        {
            if(steps.get(currentStepIndex).onBeforeFinish())
            {
                close();
                steps.get(currentStepIndex).onAfterFinish();
            }
            
        }
        else if(btnCancel.equals(event.getButton()))
        {
            if(steps.get(currentStepIndex).onBeforeCancel())
            {
                close();
                steps.get(currentStepIndex).onAfterCancel();
            }
        }
    }

    
    public static interface Step
    {
        void attachWizard(Wizard wizard);
        
        Component init();
        
        void run();
        
        boolean onBeforePrevious();
        
        void onAfterPrevious();
        
        boolean onBeforeNext();
        
        void onAfterNext();
        
        boolean onBeforeFinish();
        
        void onAfterFinish();
        
        boolean onBeforeCancel();
        
        void onAfterCancel();
    }
}
